//////////////////////////////////////////////
//                                          //
//          Alexander K. Haley's            //
//      Vector Test Pattern Generator       //
//    (For Prototype Hardware, w/o CPU)     //
//                                          //
//                Build #2                  //
//          Last edit 4/22/2020             //
//        Originally made 4/22/2020         //
//                                          //
//        (c) Alexander K. Haley            //
//                  of                      //
//            Kincaid Arcade                //
//                                          //
//////////////////////////////////////////////

//address pins
byte azero  = 22;
byte aone   = 23;
byte atwo   = 24;
byte athree = 25;
byte afour  = 26;
byte afive  = 27;
byte asix   = 28;
byte aseven = 29;
byte aeight = 30;
byte anine  = 31;
byte aten   = 32;

//data pins
byte qzero     = 38;
byte qone      = 39;
byte qtwo      = 40;
byte qthree    = 41;
byte qfour     = 42;
byte qfive     = 43;
byte qsix      = 44;
byte qseven    = 45;
byte qeight    = 46;
byte qnine     = 47;
byte qten      = 48;
byte qeleven   = 49;
//byte qtwelve   = 50; Technically, they aren't ever used...
//byte qthirteen = 51;
//byte qfourteen = 52;
//byte qfifteen  = 53;

//misc. pins
byte processorready = 33;

byte writeenable    = 34;
byte outputenable   = 35;
byte chipselect     = 36;
byte framecomplete  = 37;

byte processoroverride = 7;

byte ledpin = 12;
byte ledtwo = 11;
byte ledthree = 10;
byte errorled = 9;

//Frame Buffer
//                  1    2    3    4    5    6    7    8    9   10   11   12   13   14   15   16   17   18   19   20   21   22   23   24   25   26   27   28   29   30   31   32   33   34   35   36   37   38   39   40   41   42   43   44   45   46   47   48   49   50   51   52   53   54   55   56   57   58   59   60   61   62   63   64   65   66   67   68   69   70   71   72   73   74   75   76   77   78   79   80   81   82   83   84   85   86   87   88   89   90   91   92   93
int xcoords[93] = {512, 0,   64,  64,  0,   32,  96,  736, 800, 832, 768, 768, 832, 800, 736, 96,  32,  144, 144, 208, 208, 144, 208, 240, 240, 304, 304, 240, 272, 304, 400, 336, 336, 400, 432, 432, 496, 496, 432, 496, 528, 528, 560, 592, 592, 560, 528, 688, 624, 624, 688, 682, 624, 672, 704, 736, 736, 704, 672, 672, 640, 576, 608, 608, 640, 576, 544, 544, 480, 480, 544, 480, 448, 384, 384, 448, 352, 352, 288, 288, 256, 192, 224, 224, 256, 192, 160, 96,  160, 96,  96,  96};
int ycoords[93] = {512, 32,  96,  320, 384, 416, 352, 352, 416, 384, 320, 96,  32,  0,   64,  64,  0,   96,  192, 192, 96,  144, 144, 96,  192, 192, 144, 144, 144, 96,  96,  96,  192, 192, 96,  192, 192, 96,  144, 144, 96,  192, 192, 160, 128, 96,  96,  96,  96,  192, 192, 144, 144, 224, 224, 256, 288, 320, 320, 224, 224, 224, 224, 320, 320, 320, 224, 320, 320, 224, 272, 272, 224, 224, 320, 320, 320, 224, 320, 224, 224, 224, 224, 320, 320, 320, 320, 272, 226, 224, 320, 320};
int zvalues[93] = {0,   0,   64,  64,  64,  0,   64,  64,  64,  0,   64,  64,  64,  0,   64,  64,  64,  0,   64,  64,  64,  0,   64,  0,   64,  64,  64,  64,  0,   64,  0,   64,  64,  64,  0,   64,  64,  64,  0,   64,  0,   64,  64,  64,  64,  64,  64,  0,   64,  64,  64,  0,   64,  0,   64,  64,  64,  64,  64,  64,  0,   64,  0,   64,  0,   64,  0,   64,  64,  64,  0,   64,  0,   64,  64,  64,  0,   64,  64,  64,  0,   64,  0,   64,   0,  64,  0,   64,  64,  0,   64,  128};
//z is brightness 0-127 (8th bit signals end of frame data)
//a zero for z will have the graphics card "skip" to the location, rather than draw. Anything greater than 128 pauses graphics card.

//variables
int currentaddress  = 1;
int internaladdress = 0;
int mathaddress     = 0;

int currentdata = 0;
int mathdata    = 0;

byte bank = 0;

byte address[12];
byte data[12];


void setup() {
  // put your setup code here, to run once:

//address pins
pinMode(azero,OUTPUT);
pinMode(aone,OUTPUT);
pinMode(atwo,OUTPUT);
pinMode(athree,OUTPUT);
pinMode(afour,OUTPUT);
pinMode(afive,OUTPUT);
pinMode(asix,OUTPUT);
pinMode(aseven,OUTPUT);
pinMode(aeight,OUTPUT);
pinMode(anine,OUTPUT);
pinMode(aten,OUTPUT);

//data pins
pinMode(qzero,OUTPUT);
pinMode(qone,OUTPUT);
pinMode(qtwo,OUTPUT);
pinMode(qthree,OUTPUT);
pinMode(qfour,OUTPUT);
pinMode(qfive,OUTPUT);
pinMode(qsix,OUTPUT);
pinMode(qseven,OUTPUT);
pinMode(qeight,OUTPUT);
pinMode(qnine,OUTPUT);
pinMode(qten,OUTPUT);
pinMode(qeleven,OUTPUT);
//pinMode(qtwelve,OUTPUT);
//pinMode(qthirteen,OUTPUT);
//pinMode(qfourteen,OUTPUT);
//pinMode(qfifteen,OUTPUT);

//misc. pins
pinMode(processorready,OUTPUT);
pinMode(processoroverride,OUTPUT);

pinMode(writeenable,OUTPUT);
pinMode(outputenable,OUTPUT);
pinMode(chipselect,OUTPUT);
pinMode(framecomplete,INPUT);

pinMode(ledpin,OUTPUT);
pinMode(ledtwo,OUTPUT);
pinMode(ledthree,OUTPUT);
pinMode(errorled,OUTPUT);

digitalWrite(chipselect,LOW);
digitalWrite(outputenable,HIGH); //Make sure we're in high impedance mode.
digitalWrite(writeenable,HIGH);

//load both frame buffers with data
digitalWrite(ledpin,HIGH);
for(int x=0; x<277; x++)
  {
    computeaddress();
    computedata();
    writedata();
    currentaddress++;
  }
initiateprocessoroverride();
currentaddress = 1;
internaladdress = 0;
bank = 0;

digitalWrite(ledpin,LOW);
digitalWrite(ledtwo,HIGH);
for(int x=0; x<277; x++)
  {
    computeaddress();
    computedata();
    writedata();
    currentaddress++;
  }
vgenchecker();
currentaddress = 1;
internaladdress = 0;
bank = 0;
digitalWrite(ledtwo,LOW);
digitalWrite(ledthree,HIGH);
}

void loop() {
  // put your main code here, to run repeatedly:
//toggle active frame buffer each time the vgen sends FRAMECOMPLETE.
delay(16); //Makes the amount of frames closer to 60.
vgenchecker();
}

void computeaddress()
{
  //split address into zeros and ones
  mathaddress = currentaddress;
  
  if(mathaddress >= 1024)
    {
      digitalWrite(aten,HIGH); 
      mathaddress -= 1024; 
    }
  else
    {
      digitalWrite(aten,LOW);
    }
    
  if(mathaddress >= 512)
    {
      digitalWrite(anine,HIGH);  
      mathaddress -= 512; 
    }
  else
    {
      digitalWrite(anine,LOW);
    }
    
  if(mathaddress >= 256)
    {
      digitalWrite(aeight,HIGH);  
      mathaddress -= 256; 
    }
  else
    {
      digitalWrite(aeight,LOW);
    }
    
  if(mathaddress >= 128)
    {
      digitalWrite(aseven,HIGH);  
      mathaddress -= 128; 
    }
  else
    {
      digitalWrite(aseven,LOW);
    }
    
  if(mathaddress >= 64)
    {
      digitalWrite(asix,HIGH);  
      mathaddress -= 64; 
    }
  else
    {
      digitalWrite(asix,LOW);
    }
    
  if(mathaddress >= 32)
    {
      digitalWrite(afive,HIGH);  
      mathaddress -= 32; 
    }
  else
    {
      digitalWrite(afive,LOW);
    }
    
  if(mathaddress >= 16)
    {
      digitalWrite(afour,HIGH);  
      mathaddress -= 16; 
    }
  else
    {
      digitalWrite(afour,LOW);
    }
    
  if(mathaddress >= 8)
    {
      digitalWrite(athree,HIGH);  
      mathaddress -= 8; 
    }
  else
    {
      digitalWrite(athree,LOW);
    }
    
  if(mathaddress >= 4)
    {
      digitalWrite(atwo,HIGH);  
      mathaddress -= 4; 
    }
  else
    {
      digitalWrite(atwo,LOW);
    }
    
  if(mathaddress >= 2)
    {
      digitalWrite(aone,HIGH);  
      mathaddress -= 2; 
    }
  else
    {
      digitalWrite(aone,LOW);
    }
    
  if(mathaddress >= 1)
    {
      digitalWrite(azero,HIGH);  
      mathaddress -= 1; 
    }
  else
    {
      digitalWrite(azero,LOW);
    }

  if(mathaddress != 0)
    {
      digitalWrite(errorled,HIGH);  
    }
}

void computedata()
{
  if(bank == 3)
    {
      bank = 0;  
      internaladdress ++;
    }
  
  if(bank == 0) //x bank
    {
      currentdata = xcoords[internaladdress];
      currentdata += 96;
    }
  else if(bank == 1) //y bank
    {
      currentdata = ycoords[internaladdress];
      currentdata += 304;
    }
  else if(bank == 2) //zbank
    {
      currentdata = zvalues[internaladdress];
    }

  mathdata = currentdata;

  if(mathdata >= 2048)
    {
      digitalWrite(qeleven,HIGH); 
      mathdata -= 2048; 
    }
  else
    {
      digitalWrite(qeleven,LOW);
    }

  if(mathdata >= 1024)
    {
      digitalWrite(qten,HIGH); 
      mathdata -= 1024; 
    }
  else
    {
      digitalWrite(qten,LOW);
    }
    
  if(mathdata >= 512)
    {
      digitalWrite(qnine,HIGH);  
      mathdata -= 512; 
    }
  else
    {
      digitalWrite(qnine,LOW);
    }
    
  if(mathdata >= 256)
    {
      digitalWrite(qeight,HIGH);  
      mathdata -= 256; 
    }
  else
    {
      digitalWrite(qeight,LOW);
    }
    
  if(mathdata >= 128)
    {
      digitalWrite(qseven,HIGH);  
      mathdata -= 128; 
    }
  else
    {
      digitalWrite(qseven,LOW);
    }
    
  if(mathdata >= 64)
    {
      digitalWrite(qsix,HIGH);  
      mathdata -= 64; 
    }
  else
    {
      digitalWrite(qsix,LOW);
    }
    
  if(mathdata >= 32)
    {
      digitalWrite(qfive,HIGH);  
      mathdata -= 32; 
    }
  else
    {
      digitalWrite(qfive,LOW);
    }
    
  if(mathdata >= 16)
    {
      digitalWrite(qfour,HIGH);  
      mathdata -= 16; 
    }
  else
    {
      digitalWrite(qfour,LOW);
    }
    
  if(mathdata >= 8)
    {
      digitalWrite(qthree,HIGH);  
      mathdata -= 8; 
    }
  else
    {
      digitalWrite(qthree,LOW);
    }
    
  if(mathdata >= 4)
    {
      digitalWrite(qtwo,HIGH);  
      mathdata -= 4; 
    }
  else
    {
      digitalWrite(qtwo,LOW);
    }
    
  if(mathdata >= 2)
    {
      digitalWrite(qone,HIGH);  
      mathdata -= 2; 
    }
  else
    {
      digitalWrite(qone,LOW);
    }
    
  if(mathdata >= 1)
    {
      digitalWrite(qzero,HIGH);  
      mathdata -= 1; 
    }
  else
    {
      digitalWrite(qzero,LOW);
    }

  if(mathdata != 0)
    {
      digitalWrite(errorled,HIGH);  
    }
}

void writedata()
{
  digitalWrite(writeenable,LOW);
  digitalWrite(writeenable,HIGH);
  bank ++;
}

void initiateprocessoroverride()
{
  digitalWrite(processoroverride, HIGH);
  digitalWrite(processorready, HIGH);
  digitalWrite(processoroverride, LOW);
  digitalWrite(processorready, LOW);  
}

void vgenchecker()
{
  while(digitalRead(framecomplete) == LOW)
    {
      delayMicroseconds(1);  
    }
  if(digitalRead(framecomplete) == HIGH)
    {
      digitalWrite(processorready,HIGH);
      digitalWrite(processorready,LOW);
    }  
}
